#include "wytimer.h"
#include "time_wheel.h"
rbtimer* timermgr = NULL;

int rbt_comp_ttl_gt(void *v1, void *v2, void *argv)
{
	int ret;
	tnode *n1, *n2;
	if (v2 == NULL)
		return 1;
	if (v1 == NULL)             //v1 is null,v2 not null.
		return -1;
	n1 = (tnode *) v1;
	n2 = (tnode *) v2;
	if (tv_bigthan(n1->expired_time, n2->expired_time) > 0)
		return 1;
	if (tv_bigthan(n1->expired_time, n2->expired_time) == 0)
		return -1;

	return 0;
}




inline rbtimer* get_timer() {
	if (!timermgr)
	{
		timermgr = malloc(sizeof(rbtimer));
		timermgr->timer_queue = create_rbtree(rbt_comp_ttl_gt, NULL);
	}
	return timermgr;
}


void update_time()
{
	rbtree* rbt = get_timer()->timer_queue;
	struct timeval tcur = tv_gettimeofday();

	pthread_spin_lock(&rbt->lock);
	rbnode* rn = min_node(rbt);
	pthread_spin_unlock(&rbt->lock);
	tnode* tn = NULL;
	while (rn && rn->key)
	{
		tn = rn->key;
		if (tv_bigthan(tcur, tn->expired_time) > 0)
		{
			tn->cb(tn);
			pthread_spin_lock(&rbt->lock);
			delete_node(rbt, rn);
			pthread_spin_unlock(&rbt->lock);
			if (tn->repeat > 0)
			{
				struct timeval otv = tv_msec(tn->offset);
				if (otv.tv_sec > 60)
				{
					timer_add_timewheel(otv.tv_sec, otv.tv_usec / 1000, tn->cb, tn->param, tn->repeat);
				}
				else
				{
					tn->expired_time = tv_add(otv, tcur);
					tv_normalize(&tn->expired_time);
					rbnode node = { 0 };
					node.key = tn;
					pthread_spin_lock(&rbt->lock);
					insert_node(rbt, &node);
					pthread_spin_unlock(&rbt->lock);
				}

			}
			else
			{
				free(tn);
			}
			pthread_spin_lock(&rbt->lock);
			rn = min_node(rbt);
			pthread_spin_unlock(&rbt->lock);
		}
		else
			break;
	}
	

}

void timer_add(int sec, int msec, timercb cb, void* param ,int repeat)
{
	tnode* tn = malloc(sizeof(tnode));
	struct timeval tv;
	tv.tv_sec = sec;
	tv.tv_usec = msec * 1000;
	tn->offset = to_msec(tv);
	tn->repeat = repeat;
	tn->param = param;
	tv = tv_add(tv, tv_gettimeofday());
	tv_normalize(&tv);

	tn->expired_time = tv;
	tn->cb = cb;

	rbtree* rbt = get_timer()->timer_queue;

	rbnode node = { 0 };
	node.key = tn;
	pthread_spin_lock(&rbt->lock);
	insert_node(rbt, &node);
	pthread_spin_unlock(&rbt->lock);
}

void timer_cycle_add(int sec, int msec, struct timeval cirtv, timercb cb, void * param, int repeat)
{
	tnode* tn = malloc(sizeof(tnode));
	struct timeval tv;
	tv.tv_sec = sec;
	tv.tv_usec = msec * 1000;
	tn->offset = to_msec(cirtv);
	tn->repeat = repeat;
	tn->param = param;
	tv = tv_add(tv, tv_gettimeofday());
	tv_normalize(&tv);

	tn->expired_time = tv;
	tn->cb = cb;

	rbtree* rbt = get_timer()->timer_queue;

	rbnode node = { 0 };
	node.key = tn;
	pthread_spin_lock(&rbt->lock);
	insert_node(rbt, &node);
	pthread_spin_unlock(&rbt->lock);
}

void* do_timer(void* arg)
{
	for (;;)
	{
		update_time();
		usleep(2500);
	}
}